package main

import (
	"errors"
	"fmt"
)

/*
1. panic的使用
panic函数用于触发一个运行时异常。当程序遇到无法恢复的错误情况时，可以使用panic来中断当前的执行流程，并开始逐层向上回溯（unwind）调用栈，直到遇到一个recover调用或者程序退出。
panic通常用于处理那些严重的错误情况，例如空指针引用、数组越界等。这些错误在Go中通常通过错误返回值来处理，但在某些情况下，使用panic可以更快地中断程序执行，避免进一步的损害。
2. recover的使用
recover函数用于捕获panic触发的异常，并恢复程序的正常执行流程。recover只能在defer函数中调用，用于在函数退出前进行资源清理和错误处理。
当panc被触发时，程序会开始回溯调用栈，直到遇到一个defer函数调用中包含recover。此时，recover会捕获到异常，并返回给defer函数。defer函数可以根据需要执行一些清理操作，并决定是否重新抛出异常或者继续执行。
3. 最佳实践
谨慎使用panic：由于panic会中断程序的正常执行流程，并可能导致资源泄露和其他问题，因此应该谨慎使用。只有在确实遇到无法恢复的错误情况时，才考虑使用panic。
合理使用recover：recover应该只在defer函数中使用，并且应该谨慎处理捕获到的异常。如果recover成功捕获了异常，最好记录错误并尝试恢复程序的正常执行。如果无法恢复，可以考虑重新抛出异常或者采取其他适当的措施。
避免滥用panic和recover：虽然panic和recover提供了异常处理的能力，但它们并不是Go语言的主要错误处理机制。在大多数情况下，应该优先考虑使用错误返回值来处理错误情况。只有当错误情况确实无法通过正常的错误处理机制来解决时，才考虑使用panic和recover。
总结
Go语言中的异常处理机制通过panic和recover提供了处理严重错误情况的能力。虽然它们不是主要的错误处理机制，但在某些情况下可以非常有用。通过谨慎使用panic和recover，并遵循最佳实践，可以确保程序的健壮性和稳定性。
在Go语言中除了返回error类型的返回值，还有panic异常，panic会使策程序崩溃退出，panic分为我们主动使用painc()函数定义和被动触发
recover是用防止panic导致程序退出，并捕获panic异常
*/

func testError2(a, b int) (int, error) {
	c := a + b
	fmt.Println("发生painc之前")
	panic("发生panic异常") // 测试时可以打开注释
	fmt.Println("发生painc之后")
	return c, errors.New("this is an error") //有些我们需要使用errors来返回异常的内容，有的会只带默认内容
}

func testError3() int {
	var map1 map[int]string
	defer func() {
		// recover只有在defer调用的函数中才生效，所以recover需要和defer搭配使用
		if error := recover(); error != nil {
			fmt.Printf("捕获被动panic recover %v\n", error)
		}
	}()
	fmt.Println("触发被动painc之前")
	map1[1] = "go" //在这里由于map没有初始化，这里会被动触发painc
	fmt.Println("触发被动painc之后")
	return 2
}

func main() {
	/*
		一、调用主动panic
	*/
	result, err := testError2(1, 2)
	fmt.Println(result, err)
	fmt.Println("没有使用recover外部程序和子函数一样崩溃")
	// 结果：
	//发生painc之前
	//panic: 发生panic异常
	// 可以看得出，panic之后的逻辑不会执行

	/*
		二、使用recover捕获panic(当然主动触发和被动触发的都可以捕获)，使程序不崩溃，但是出现panic的子函数中后面的逻辑也不会执行
	*/
	testError3()
	fmt.Println("采用recover外部程序继续执行") // 这一行继续执行，采用recover之后，捕获子函数的panic，并继续执行外部函数逻辑
}

/*
注意点：
1、defer需要放到panic之前定义，recover只有在defer调用的函数中才生效
2、recover处理异常后，逻辑并不会恢复到panic那个点去，会有部分丢失
*/
